使用AspectJ实现AOP
Aspect简介
AspectJ是一个基于Java语言的AOP框架
Spring2.0以后新增了对AspectJ切点表达式支持
@AspectJ是AspectJ 1.5新增的功能,通过JDK5注解技术,允许直接在Bean类中定义切面
新版本Spring框架,建议使用AspectJ方式来开发AOP
1 2 3 4 5
| 使用AspectJ需要引入Spring AOP和AspectJ相关Jar包: spring-aop aopalliance spring-aspects aspectjweaver
|
案例使用的代码:
https://github.com/hzebin/SpringAOP_AspectJ
使用AspectJ是,xml配置文件格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
|
@AspectJ提供的通知类型
通知类型 |
说明 |
@Before |
前置通知,相当于BeforeAdvice |
@AfterReturning |
后置通知,相当于AfterReturningAdvice |
@Around |
环绕通知,相当于AfterReturningAdvice |
@AfterThrowing |
异常抛出通知,相当于ThrowAdvice |
@After |
最终通知(相当于try-catch的finally),不管是否异常,该通知都会执行 |
@DeclareParents |
引介通知,相当于IntroductionInterceptor |
使用的例子(注解方式)
step1:创建Maven项目(Webapp)
step2:引入jar包
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
| <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>cn.hzebin</groupId> <artifactId>im_spring_aspect</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging>
<name>im_spring_aspect Maven Webapp</name> <url>http://www.example.com</url>
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.7</maven.compiler.source> <maven.compiler.target>1.7</maven.compiler.target> </properties>
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.2.4.RELEASE</version> </dependency>
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>4.2.4.RELEASE</version> </dependency>
<dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.2.4.RELEASE</version> </dependency>
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>4.2.4.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>compile</scope> </dependency> </dependencies>
<build> <finalName>im_spring_aspect</finalName> <pluginManagement> <plugins> <plugin> <artifactId>maven-clean-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <artifactId>maven-resources-plugin</artifactId> <version>3.0.2</version> </plugin> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> </plugin> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.1</version> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.2</version> </plugin> <plugin> <artifactId>maven-install-plugin</artifactId> <version>2.5.2</version> </plugin> <plugin> <artifactId>maven-deploy-plugin</artifactId> <version>2.8.2</version> </plugin> </plugins> </pluginManagement> </build> </project>
|
step3 - 1:创建目标类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package cn.hzebin.demo1;
public class ProductDao { public void add() { System.out.println("增加操作"); }
public void update() { System.out.println("修改操作"); }
public void find() { System.out.println("查询操作"); }
public void delete() { System.out.println("删除操作"); } }
|
step3 - 2:创建切面类
JoinPoint类可以获得切入点信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package cn.hzebin.demo1;
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;
@Aspect public class MyAspectAnno {
@Before(value = "execution(* cn.hzebin.demo1.ProductDao.add(..))") public void before(JoinPoint joinPoint) { System.out.println("前置通知" + joinPoint); } }
|
step4:创建applicationContext.xml配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<bean id="productDao" class="cn.hzebin.demo1.ProductDao"></bean>
<bean class="cn.hzebin.demo1.MyAspectAnno"></bean> </beans>
|
step5:使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package cn.hzebin.demo1;
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringDemo1 { @Resource(name = "productDao") private ProductDao productDao;
@Test public void demo1() { productDao.add(); productDao.delete(); productDao.find(); productDao.update(); } }
|
@Before前置通知
可以在方法中传入JoinPoint对象,用来获得切点的信息
1 2 3 4 5 6 7
|
@Before(value = "execution(* cn.hzebin.demo1.ProductDao.add(..))") public void before(JoinPoint joinPoint) { System.out.println("==前置通知==,可以获得切入点信息" + joinPoint); }
|
@AfterReturning后置通知
通过returning属性,可以定义方法返回值,作为参数
1 2 3 4 5
| @AfterReturning(value = "execution(* cn.hzebin.demo1.ProductDao.update(..))", returning = "result") public void demo2(Object result) { System.out.println("==后置通知==,可以获得切入点的返回值 -> " + result); }
|
@Around环绕通知
around方法的返回值就是目标代理方法执行返回值
参数为ProceedingJoinPoint,可以拦截目标方法的执行
1 2 3 4 5 6 7 8
| @Around(value = "execution(* cn.hzebin.demo1.ProductDao.delete(..))") public Object demo3(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("环绕前的通知"); Object obj = joinPoint.proceed(); System.out.println("环绕后的通知"); return obj; }
|
@AfterThrowing异常通知
通过设置throwing属性,可以设置发生异常对象参数
1 2 3 4 5
| @AfterThrowing(value = "execution(* cn.hzebin.demo1.ProductDao.find(..))", throwing = "e") public void demo4(Throwable e) { System.out.println("异常通知," + e.getMessage()); }
|
@After最终通知
无论是否发生异常,最终通知总是会被执行
1 2 3 4 5
| @After(value = "execution(* cn.hzebin.demo1.ProductDao.findOne(..))") public void demo5() { System.out.println("最终通知"); }
|
@Pointcut可以给切点命名
- 在每个通知内定义切点,会造成工作量大,不易维护,对于重复的切点,可以使用@Pointcut进行定义
- 切点方法:private void 切点名() {}
- 当通知多个切点时,可以使用||进行连接
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package cn.hzebin.demo2;
import org.aspectj.lang.annotation.*;
@Aspect public class AspectAnno { @Before(value = "myPointCut1() || myPointCut2()") public void demo1() { System.out.println("前置通知"); }
@AfterReturning(value = "myPointCut2()", returning = "result") public void demo2(Object result) { System.out.println("后置通知" + result); }
@Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.add(..))") private void myPointCut1() {}
@Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.delete(..))") private void myPointCut2() {}
@Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.update(..))") private void myPointCut3() {}
@Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.findOne(..))") private void myPointCut4() {}
@Pointcut(value = "execution(* cn.hzebin.demo2.ProductDao.findAll(..))") private void myPointCut5() {} }
|
Aspect的XML配置
== 【unfinish】 ==